package se.webbzon.boltzmann.battle.battleaction.projectile;

import java.util.ArrayList;
import java.util.Collection;

import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;

import se.webbzon.boltzmann.battle.object.npc.BattleNPC;
import se.webbzon.boltzmann.projectile.Projectile3D;
import se.webbzon.oschi01.worldarea.WorldArea;
import se.webbzon.oschi01.worldobject.WorldMovableObject;
import se.webbzon.oschi01.worldobject.WorldObject;
import se.webbzon.oschi01.worldobject.appearance.Appearance3D;

public abstract class AbstractBattleProjectile extends WorldMovableObject {
	
	// A collection of all the listeners to this battle projectile
	private final Collection<BattleProjectileListener> listeners; 
	
	// The vertical acceleration of the projectile
	private final double acceleration;
	
	// The target of this battle projectile
	private final Point3d target;
	
	// An optional object target
	private final BattleNPC objectTarget;
	
	// The startup duration and remaining time (# of steps) until the 
	// projectile has reached its target
	private final int duration;
	private int remaining;
	
	/*============================================================
	Constructors
	============================================================*/

	/** Creates a new battle projectile associated with the given battle
	 * action. A target, horizontal speed, vertical acceleration and
	 * 3-dimensional appearance must be provided.**/
	public AbstractBattleProjectile(BattleNPC target, 
							int duration, double acceleration,
							Appearance3D appearance) {
		super(WorldObject.onCreate + WorldObject.onStep, appearance);
		this.listeners = new ArrayList<BattleProjectileListener>();
		this.acceleration = acceleration;
		this.target = new Point3d();
		this.duration = duration;
		objectTarget = target;
		
	}
	
	/** Creates a new battle projectile associated with the given battle
	 * action. A target, horizontal speed, vertical acceleration and
	 * 3-dimensional appearance must be provided.**/
	public AbstractBattleProjectile(Point3d target, 
							int duration, double acceleration,
							Appearance3D appearance) {
		super(WorldObject.onCreate + WorldObject.onStep, appearance);
		this.listeners = new ArrayList<BattleProjectileListener>();
		this.acceleration = acceleration;
		this.target = new Point3d(target);
		this.duration = duration;
		objectTarget = null;
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Adds a listener to this battle projectile. **/
	public boolean addListener(BattleProjectileListener listener) {
		return listeners.add(listener);
	}
	
	/** Removes a listener to this battle projectile. **/
	public boolean removeListener(BattleProjectileListener listener) {
		return listeners.remove(listener);
	}
	
	/** Clears all the listeners from this battle projectile. **/
	public void clearListeners() {
		listeners.clear();
	}
	
	/** Returns true if the battle projectile has a non-player character
	 * target. **/
	public boolean hasTarget() {
		return (objectTarget != null);
	}
	
	/** Returns the non-player character target of the battle projectile. **/
	public BattleNPC getTarget() {
		return objectTarget;
	}
	
	@Override public void onCreate(WorldArea world) {
		if (objectTarget != null)
			objectTarget.getPosition(target);
		
		Vector3d v = Projectile3D.getVelocity(getPosition(), target, acceleration, duration);
		setVelocity(v.getX(), v.getY(), v.getZ());
		setAcceleration(0,acceleration,0);
		
		remaining = duration + 2;
	}
	
	@Override public void onStep(WorldArea world) {
		if (remaining == 0) {
			for (BattleProjectileListener listener : listeners)
				listener.onReachTarget(this);
			world.destroyInstance(this);
		} else
			remaining--;
	}

}
